<?php

namespace app\common\service;

use app\common\domain\Express as ExpressDomain;
use app\common\enum\ExpressStatusEnum;
use app\common\exception\Client;
use app\common\exception\Server;
use app\common\model\Express as ExpressModel;
use app\common\service\ExpressDailyStats as ExpressDailyStatService;
use app\common\service\ExpressTimeline as ExpTimelineService;
use app\common\service\User as UserService;
use app\common\service\Warehouse as WarehouseService;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Config;
use think\facade\Db;
use think\Paginator;
use think\Response\Json;

class Express
{
    /**
     * 添加快递信息
     * @param string $trackingNumber
     * @return Json
     * @throws Client
     * @throws DbException|Server
     */
    public static function addExpress(string $trackingNumber): Json
    {
        // 2调用领域层获取数据
        $expressDomain = new ExpressDomain();
        $expressDomain->generateExpressData($trackingNumber);
        // 3. 调用服务层获取开放货架层
        $shelfLayer = WarehouseService::getActiveShelfLayer($expressDomain->expressData['company_code']);
        //4.获取该快递公司自增序号
        $sequence = ExpressDailyStatService::getAndIncSequence($expressDomain->expressData['company_code']);
        //5.生成取件码
        $pickupCode = $expressDomain->generatePickupCode($expressDomain->expressData['company_code'],$shelfLayer,$sequence);
        $expressDomain->expressData['pickup_code'] = $pickupCode;

        //        // 1. 检查单号是否已存在
        $exists = ExpressModel::where('tracking_number', $trackingNumber)
            ->where('create_time', '>', time() - 172800)
            ->count();

        if ($exists) return writeJson(200,[], '已入库');
        //6.调用模型层操作数据库
        Db::startTrans();
        try {
            $express = ExpressModel::create($expressDomain->expressData);
            (new ExpTimelineService())->creatEvent($express->id,ExpressStatusEnum::STORED);
            $express->clearCacheByTag();
            Db::commit();
            //7.标准化响应
            return writeJson(200, $expressDomain->expressData, '入库成功');
        }catch (Exception $e){
            Db::rollback();
            throw new Server($e->getMessage());
        }
    }

    /**
     * 取件码预约
     * @param $params
     * @param $token
     * @return void
     * @throws Client
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws Server
     */
    public static function codeReservation($params,$token){
        $express = ExpressModel::where('pickup_code',$params['pickup_code'])->where('create_time', '>', time() - 7776000)->find();
        if($express) throw new Client(223001,'该快递已预约');
        $expressDomain = new ExpressDomain();
        $params = $expressDomain->getTimeSlot($params);
        $params['user_id'] = (new UserService())->getUserIdFromToken($token);
        $params['status'] = ExpressStatusEnum::RESERVED;
        Db::startTrans();
        try{
            $express = ExpressModel::create($params);
            (new ExpTimelineService())->creatEvent( $express->id,ExpressStatusEnum::RESERVED);
            $express->clearCacheByTag();
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            throw new Server($e->getMessage());
        }
    }


    /**
     * 客户预约快递
     * @param $params
     * @param $token
     * @return void
     * @throws Client
     * @throws DbException
     * @throws DataNotFoundException
     * @throws ModelNotFoundException|Server
     */
    public function reservation($params,$token)
    {
        $express = ExpressModel::where('tracking_number',$params['tracking_number'])->find();
        if(!$express) throw new Client(223001,'未查到该快递');
        if($express->status!=ExpressStatusEnum::STORED)throw new Client(223001,'该快递请求参数状态非法');//若快递不是入库状态，报错
        $expressDomain = new ExpressDomain();
        $params = $expressDomain->getTimeSlot($params);
        $user_id = (new UserService())->getUserIdFromToken($token);
        $express->user_id = $user_id;
        $express->status = ExpressStatusEnum::RESERVED;
        $express->address = $params['address'];
        $express->mobile = $params['mobile'];
        $express->appt_type = $params['appt_type'];
        $express->start_time = $params['start_time'];
        $express->end_time = $params['end_time'];
        Db::startTrans();
        try{
            $express->save();
            (new ExpTimelineService())->creatEvent( $express->id,ExpressStatusEnum::RESERVED);
            $express->clearCacheByTag();
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            throw new Server($e->getMessage());
        }

    }

    /**
     * 分页获取快递列表信息
     * @param $params
     * @param $token
     * @return Paginator
     * @throws Client
     */
    public function list($params,$token='')
    {
        if($token){$params['user_id'] = (new UserService())->getUserIdFromToken($token);}
        $expressDomain = new ExpressDomain();
        $res = $expressDomain->getListCondition($params);
        $result =  (new ExpressModel())->paginateList(
            $res['where'],
            $res['page'],
            $res['pageSize'],
            $res['order']
        );
        return $result;
    }

    /**
     * 客户签收快递
     * @param $params
     * @param $token
     * @return void
     * @throws Client
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function signIn($params,$token){
        $user_id = (new UserService())->getUserIdFromToken($token);
        $express = ExpressModel::where('user_id',$user_id)->find($params['id']);
        if(!$express)throw new Client(223001,'未查到该快递，请联系工作人员');
        if($express->status==ExpressStatusEnum::RECEIVED)throw new Client(223001,'已签收快递');
        if($express->status!=ExpressStatusEnum::DELIVERED)throw new Client(223001,'还未送达，请不要签收');
        $express->status = ExpressStatusEnum::RECEIVED;

        Db::startTrans();
        try{
            $express->save();
            (new ExpTimelineService())->creatEvent( $express->id,9);
            $express->clearCacheByTag();
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            throw new Server($e->getMessage());
        }

    }

    /**
     * cms更新换快递状态
     * @param $params
     * @return void
     * @throws Client
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function updateStatus($params){
        $express = ExpressModel::find($params['id']);
        if(!$express)throw new Client(223001,'未查到该快递');
        //判断状态
        if($params['status']<=$express->status)throw new Client(223001,'该快递请求参数状态非法');
        $express->status = $params['status'];
        Db::startTrans();
        try{
            $express->save();
            (new ExpTimelineService())->creatEvent( $express->id,9);
            $express->clearCacheByTag();
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            throw new Server($e->getMessage());
        }
    }

    /**
     * 获取快递公司与时间段信息
     * @return mixed
     */
    public function getCompanyAndTime()
    {
        $companyInfo = Config::get('express.company');
        $timeSlot = filterDeliveryTimes(Config::get('time.deliveryTimes'));
        return [
            'companyInfo' => $companyInfo,
            'timeSlot' => $timeSlot,
        ];
    }













}